using UnityEngine;
using System.Collections;
using System.Collections.Generic;


[RequireComponent(typeof(Collider))]
public class Injury : CharacterAction
{
	public int injury = 200;
	public bool fall = false; 
	public float pushForward;

    public bool finalAttack;//it's final attack usually used in end of kuso
    public float finalPushForward;//if it is final attack
    public bool finalFall;

	public float blowUp;
	public float interval = -1;
    public int receiverDelayFrames = -1;
    public int senderDelayFrames = -1;
    public int receiverPushFrames = -1;
	public int breakDefence = 0;

	public bool touchEvading = false;

	public HitEffect effect;

	protected List<Character> hitten = new List<Character>(); 
	protected List<float> hitTime = new List<float>(); 
	protected Collider colliderRef;
    public Transform refTrans;

    //Shake
    public ShakeCameraData shakeData;
    public bool willShake = false;
    private bool defaultShake;

	public override void Init(CharacterKeyFrame frame)
	{
		base.Init(frame);

		colliderRef = collider;
		colliderRef.enabled = false;
		colliderRef.isTrigger = true;

        defaultShake = willShake;
	}

	public override void OnActionEnter (Character character)
	{
		base.OnActionEnter (character);
		colliderRef.enabled = true;
		ClearHitten();
		if(interval == -1)
		{
			hitten.Clear();
			hitTime.Clear();
		}
		character.rigidbodyRef.WakeUp(); 
		//injury = character.Property.strength + character.Property.weapon.power;
        willShake = defaultShake;
    }

	public override void OnActionExit (Character character)
	{
		base.OnActionExit (character);
		colliderRef.enabled = false;

        foreach(Character c in hitten)
        {
            character.LockTarget = c;
        }

	}

	public override void OnFrameUpdate (Character.FrameUpdate arg)
	{
		bool wakeup = ClearHitten();

		if(wakeup)
		{
			colliderRef.enabled = false;
			colliderRef.enabled = true;
			character.rigidbodyRef.WakeUp(); 
		}
        if(refTrans != null)
        {
            transform.position = refTrans.position;
        }
	}
 
	bool ClearHitten()
	{
		if(interval == -1)
			return false;

		bool wakeup = false;
		for(int i = hitten.Count - 1; i >= 0; i--)
		{
			if(Time.fixedTime - hitTime[i] >= interval)
			{
				hitten.RemoveAt(i);
				hitTime.RemoveAt(i);
				wakeup = true;
			}
		}
		return wakeup;
	}

	void Hit(Character sender, Character receiver)
	{
		InjuryInformation info = new InjuryInformation();
		info.injury = injury;
		info.fall = fall;
		info.breakDefense = breakDefence;

        float push = pushForward;
        if(state.IsLastLoop() && finalAttack)
        {
            push = finalPushForward;
            info.fall = finalFall;//final attack will make it fall
        }

        info.push = push * sender.transform.forward + blowUp * sender.transform.up;
		info.receiverDelayFrames = receiverDelayFrames;
        info.senderDelayFrames = senderDelayFrames;
        info.receiverPushFrames = receiverPushFrames;
 
		SendHittingInfo(info,sender,receiver);
		effect.OnHit(sender, receiver, info);

        if(willShake)
        {
            willShake = false;
            CameraFollow.instance.Shake(shakeData);
        }
	}

    public static void SendHittingInfo(InjuryInformation info,Character sender, Character receiver)
	{
		// receiver shouldn't be null
		if(sender.onHitting.listened)
		{
			Character.Hitting message = new Character.Hitting();
			message.character = sender;
			message.receiver = receiver;
			message.injury = info;
			sender.onHitting.SendEventMessage(message);
		}
		
		if(sender.onDamaged.listened)
		{
			if(receiver != null){//maybe died 
				Character.Damaged message = new Character.Damaged();
				message.character = receiver;
	            message.sender = sender;
	            message.injury = info;
	            receiver.onDamaged.SendEventMessage(message);
			}
        }
	} 

	void OnTriggerEnter(Collider other) 
	{ 
		if(other.isTrigger == false)
		{  
			Character receiver = other.GetComponent<Character>();
			if(receiver == null || hitten.Contains(receiver))
            {
				return;
            }
			if(receiver.gameObject.layer == character.gameObject.layer)//enemy in same layer means no damage
			{
				return;
			}

			switch(receiver.bodyState)
			{
			case BodyState.Inactive:
				return;
			case BodyState.Evading:
				if(touchEvading)
					return;
				else
					break;
			default:
				break;
			}

			hitten.Add(receiver);
			hitTime.Add(Time.fixedTime);

			Hit(character, receiver);
		}
	}
}

